package omg.Persistance;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import omg.DbHandling.DatabaseInt;
import omg.Error.DBError;
import omg.Error.PersistanceError;
import omg.OMGApp;
import omg.SongHandling.DataHandling.*;
import omg.UserInterfaces.UserInt;
import org.jdesktop.application.Task;

public class PersistanceInt extends Task<Void, Void> {

    static final String TARGET_FORMAT = "mp3";
    private static PersistanceInt instance = null;
    private Song song;
    private String name;

    public PersistanceInt() {
        super(OMGApp.getApplication());
    }

    ;

    public void setSong(Song song) {
        this.song = song;
    }

    public void setName(String name) {
        this.name = name;
    }

//    public static PersistanceInt getInstance() {
//        if (null == PersistanceInt.instance) {
//            PersistanceInt.instance = new PersistanceInt();
//        }
//        return PersistanceInt.instance;
//    }
    /**
     * Persists a song by downloading, converting it and finally moving it
     * to the provided target location.
     * @param song the song to persist
     * @param name the target file name, without format ending and location
     * @throws PersistanceError
     * @throws DBError
     */
    public void persist(Song song, String name) throws PersistanceError, DBError {
        try {
            File tmp_file = File.createTempFile("omg", (new File(song.getLink().getPath())).getName());
            System.out.println("Creating temp file for the download: " + tmp_file.toString());
            File target_file = new File(DatabaseInt.getInstance().getConfigValue("StoreLocation")+ "/" + name + "." + TARGET_FORMAT);
            download(song, tmp_file);
            convert(tmp_file, target_file);
            if (!target_file.exists() || 0 == target_file.length()) {
                deleteDirs(target_file.getParentFile(), new File(DatabaseInt.getInstance().getConfigValue("StoreLocation")));
                throw new PersistanceError("The persist file doesn't exist at the target location!");
            }
        } catch (IOException ex) {
            throw new PersistanceError(ex);
        } catch (InterruptedException ex) {
            throw new PersistanceError(ex);
        }
    }

    /**
     * Downloads a song using wget.
     * @param song
     * @param target
     */
    private void download(Song song, File target) throws IOException, InterruptedException {
        System.out.println("Geting: " + song.getLink().toString() + ", to: " + target.toString());
        int size = song.getLink().toURL().openConnection().getContentLength();
        System.out.println("File size is: " + String.valueOf(size));
        java.io.BufferedInputStream in = new java.io.BufferedInputStream(song.getLink().toURL().openStream());
        java.io.FileOutputStream fos = new java.io.FileOutputStream(target.toString());
        java.io.BufferedOutputStream bout = new BufferedOutputStream(fos, 1024);
        byte[] data = new byte[1024];
        int x = 0;
        float downloaded = 0;
        int progress = 0;

        while ((x = in.read(data, 0, 1024)) >= 0) {
            downloaded += 1024;
            bout.write(data, 0, x);
            if ((int) ((downloaded / size) * 100) > progress) {
                progress = (int) ((downloaded / size) * 100);
                UserInt.getInstance().setProgressState(progress);
            }
        }
        bout.close();
        in.close();
    }

    /**
     * Converts a Song using ffmpeg.
     * @param source
     * @param target
     */
    private void convert(File source, File target) throws IOException, InterruptedException {
        target.getParentFile().mkdirs();
        System.out.println("Generating directory tree: " + target.toString());
        DatabaseInt configuration = omg.DbHandling.DatabaseInt.getInstance();
        try {
            File ffmpegPath = new File(configuration.getConfigValue("ffmpegLocation"));
            String[] cmd = {ffmpegPath.toString(), "-i", source.getAbsolutePath(), target.getAbsolutePath()};
            Process p = Runtime.getRuntime().exec(cmd);
            p.waitFor();
        } catch (Exception ex) {
        }
    }

    /**
     * Delete all dirs until the first non-empty or unti end directory is
     * reached.
     * @param dir
     * @param end
     */
    private void deleteDirs(File dir, File end) {
        if (dir.toString().equalsIgnoreCase(end.toString())) {
            return;
        }


        if (dir.isDirectory()) {
            if (0 != dir.list().length) {
                return;
            } else {
                dir.delete();
                deleteDirs(
                        dir.getParentFile(), end);

            }
        }
    }

    @Override
    protected Void doInBackground() throws Exception {
        try {
            boolean done = false;
            File tmpFile = File.createTempFile("omg", (new File(song.getLink().getPath())).getName());
            System.out.println("Creating temp file for the download: " + tmpFile.toString());
            File targetFile = new File(DatabaseInt.getInstance().getConfigValue("StoreLocation") + System.getProperty("file.separator") + this.name + "." + TARGET_FORMAT);

            System.out.println("Geting: " + this.song.getLink().toString() + ", to: " + targetFile.toString());
            int size = this.song.getLink().toURL().openConnection().getContentLength();
            System.out.println("File size is: " + String.valueOf(size));

            java.io.BufferedInputStream in = new java.io.BufferedInputStream(song.getLink().toURL().openStream());
            java.io.FileOutputStream fos = new java.io.FileOutputStream(tmpFile.toString());
            java.io.BufferedOutputStream bout = new BufferedOutputStream(fos, 1024);

            byte[] data = new byte[1024];
            int x = 0;
            float downloaded = 0;
            int progress = 0;

            while ((x = in.read(data, 0, 1024)) >= 0) {
                downloaded += 1024;
                bout.write(data, 0, x);
                if ((int) ((downloaded / (size * 1.4)) * 100) > progress) {
                    progress = (int) ((downloaded / (size * 1.4)) * 100);
                    UserInt.getInstance().setProgressState(progress);
                }
            }
            bout.close();
            in.close();


            targetFile.getParentFile().mkdirs();
            System.out.println("Generating directory tree: " + targetFile.toString());
            DatabaseInt configuration = omg.DbHandling.DatabaseInt.getInstance();
            try {
                File ffmpegPath = new File(configuration.getConfigValue("ffmpegLocation"));
                String[] cmd = {ffmpegPath.toString(), "-i", tmpFile.getAbsolutePath(), targetFile.getAbsolutePath()};
                Process p = Runtime.getRuntime().exec(cmd);
                p.waitFor();
            } catch (Exception ex) {
            }

            if (!targetFile.exists() || 0 == targetFile.length()) {
                deleteDirs(targetFile.getParentFile(), new File(DatabaseInt.getInstance().getConfigValue("StoreLocation")));
                throw new PersistanceError("The persist file doesn't exist at the target location!");
            }
            System.out.println("Download finished");
            done = true;
        } catch (IOException ex) {
            throw new PersistanceError(ex);
        }
        return null;
    }
}
